package com.wh1200.mybatis.xmlless.config

import com.wh1200.mybatis.xmlless.enums.XmllessDbType
import com.wh1200.mybatis.xmlless.handler.JsonTypeHandler
import com.wh1200.mybatis.xmlless.replaceSpace
import com.wh1200.xmlless.test.dao.UserDAO
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
import kotlin.reflect.jvm.javaMethod
import kotlin.test.assertContains
import kotlin.test.assertNotNull
import org.slf4j.Logger
import org.slf4j.LoggerFactory


/**
 *
 * Created by 吴昊 on 2018-12-09.
 *
 * @author 吴昊
 * @since 0.0.1
 */
class UserDAOResolverTest : BaseResolverTest(
    UserDAO::class.java
) {

  @Test
  fun resolveFindAll() {
    val q = createQueryForMethod(UserDAO::findAll.javaMethod!!)
    val sql = q.sql
    q.exception?.printStackTrace()
    assertNotNull(sql)
    if (dbType == XmllessDbType.MYSQL) {
      assertContains(sql, "JSON_CONTAINS(t_user.roles, CAST(roles_t_role.id AS JSON), '\$')")
      assertContains(sql, "JSON_CONTAINS(roles_t_role.deps, CAST(roles_t_role_deps_t_dep.id AS JSON), '\$')")
    } else if (dbType == XmllessDbType.POSTGRE_SQL) {
      assertContains(sql, "(roles_t_role.deps)::jsonb @> (roles_t_role_deps_t_dep.id)::jsonb")
      assertContains(sql, "(roles_t_role.deps)::jsonb @> (roles_t_role_deps_t_dep.id)::jsonb")
    }
  }

  @Test
  @DisplayName("多个条件中包含特殊值并用or连接")
  fun resolveFindByOrConditions() {
    val q = createQueryForMethod(UserDAO::find666.javaMethod!!)
    q.exception?.printStackTrace()
    val sql = q.sql
    q.exception?.printStackTrace()
    assertNotNull(sql)
    val c = q.query?.criterion
    assertNotNull(c)
  }

  @Test
  @DisplayName("测试contains any")
  fun resolveContainsAny() {
    val q = createQueryForMethod(UserDAO::findByAnyRole.javaMethod!!)
    q.exception?.printStackTrace()
    val sql = q.sql
    assertNotNull(sql)
    if (dbType == XmllessDbType.POSTGRE_SQL) {
      println(sql)
    } else {
      assertContains(sql, "JSON_CONTAINS(t_user.roles")
    }
  }

  @Test
  @DisplayName("查询join对象中的字段")
  fun resolveFindJoinField() {
    val q = createQueryForMethod(UserDAO::findStudentNameById.javaMethod!!)
    q.exception?.printStackTrace()
    val sql = q.sql
    assertNotNull(sql)
    assertContains(sql, "student.name")
    assertContains(sql, "LEFT JOIN")
    assertContains(sql, "student.id = t_user.student_id")
    assertContains(sql, "t_user.id = #{id}")
  }

  @Test
  @DisplayName("查询join对象中的字段")
  fun resolveFindJoinField2() {
    val q = createQueryForMethod(UserDAO::findStudentNameById2.javaMethod!!)
    q.exception?.printStackTrace()
    val sql = q.sql
    assertNotNull(sql)
    assertContains(sql, "student.email")
    assertContains(sql, "LEFT JOIN")
    assertContains(sql, "student.id = t_user.student_id")
  }

  @Test
  fun findById() {
    val method = UserDAO::findById.javaMethod!!
    val q = createQueryForMethod(method)
    val sql = q.sql
    assertNotNull(sql)
    assertContains(sql, "AS department_id")
  }

  @Test
  @DisplayName("从数组中移除元素")
  fun removeElementFromJsonArray() {
    val q = createQueryForMethod(UserDAO::updateRolesRemoveRoleById.javaMethod!!)
    val sql = q.sql
    assertNotNull(sql)
  }

  @Test
  fun resolvePartlyUpdate() {
    val query = createQueryForMethod(UserDAO::update.javaMethod!!)
    val sql = query.sql
    assertNotNull(sql)
    assertContains(
        sql.replaceSpace(), """<if test="name != null"> name = #{name}, </if>""".trimMargin()
    )
  }

  @Test
  fun resolveSave() {
    val query = createQueryForMethod(UserDAO::save.javaMethod!!)
    val sql = query.sql
    assertNotNull(sql)
    assertContains(sql, "#{roles, typeHandler=${JsonTypeHandler::class.java.name}}")
  }

  @Test
  fun resolveResultMap() {
    val method = UserDAO::findAll.javaMethod!!
    createQueryForMethod(method)
    val resultMaps = builderAssistant.configuration.resultMaps
    val ids = resultMaps.map { it.id }
    assert(ids.contains(buildResultMapId(method)))
  }

  @Test
  @DisplayName("查找关联对象集合")
  fun findRoleList() {
    val method = UserDAO::findRoleListById.javaMethod!!
    val q = createQueryForMethod(method)
    val resultMaps = builderAssistant.configuration.resultMaps
    val id = buildResultMapId(method)
    val resultMap = resultMaps.find { it.id == id }
    assertNotNull(resultMap)
  }

  companion object {
    private val log: Logger = LoggerFactory.getLogger(UserDAOResolverTest::class.java)
  }

}
